//
//  NSThread+YYAdd.m
//  YYKit <https://github.com/ibireme/YYKit>
//
//  Created by ibireme on 15/7/3.
//  Copyright (c) 2015 ibireme.
//
//  This source code is licensed under the MIT-style license found in the
//  LICENSE file in the root directory of this source tree.
//

#import "NSThread+YYAdd.h"
#import <CoreFoundation/CoreFoundation.h>
#import <objc/runtime.h>

@interface NSThread_YYAdd : NSObject @end
@implementation NSThread_YYAdd @end

extern void *objc_autoreleasePoolPush(void);
extern void objc_autoreleasePoolPop(void *context);

// MARK: - 私有常量
static NSString *const YYNSThreadAutoreleasePoolKey = @"YYNSThreadAutoreleasePoolKey";
static NSString *const YYNSThreadAutoreleasePoolStackKey = @"YYNSThreadAutoreleasePoolStackKey";

// 回调：用于 CFArray 存储 void* 指针（autorelease pool context）
static const void* PoolStackRetain(CFAllocatorRef allocator, const void *value) {
    return value;
}

static void PoolStackRelease(CFAllocatorRef allocator, const void *value) {
    // 注意：这里不需要对 context 做 release，objc_autoreleasePoolPop 已处理
}

// MARK: - 内联函数：Push / Pop
static inline void YYAutoreleasePoolPush(void) {
    NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
    // 修复：添加__bridge关键字，将id转换为CFMutableArrayRef
    CFMutableArrayRef poolStack = (__bridge CFMutableArrayRef)dict[YYNSThreadAutoreleasePoolStackKey];

    if (!poolStack) {
        CFArrayCallBacks callbacks = kCFTypeArrayCallBacks;
        callbacks.retain = PoolStackRetain;
        callbacks.release = PoolStackRelease;
        poolStack = CFArrayCreateMutable(NULL, 0, &callbacks);
        dict[YYNSThreadAutoreleasePoolStackKey] = (__bridge id)poolStack;
        CFRelease(poolStack);
    }

    void *pool = objc_autoreleasePoolPush();
    CFArrayAppendValue(poolStack, pool);
}

static inline void YYAutoreleasePoolPop(void) {
    NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
    // 修复：添加__bridge关键字，将id转换为CFMutableArrayRef
    CFMutableArrayRef poolStack = (__bridge CFMutableArrayRef)dict[YYNSThreadAutoreleasePoolStackKey];

    if (!poolStack || CFArrayGetCount(poolStack) == 0) {
        return;
    }

    void *pool = (void *)CFArrayGetValueAtIndex(poolStack, CFArrayGetCount(poolStack) - 1);
    CFArrayRemoveValueAtIndex(poolStack, CFArrayGetCount(poolStack) - 1);
    objc_autoreleasePoolPop(pool);
}

// MARK: - RunLoop Observer 回调
static void YYRunLoopAutoreleasePoolObserverCallback(CFRunLoopObserverRef observer,
                                                     CFRunLoopActivity activity,
                                                     void *info) {
    switch (activity) {
        case kCFRunLoopEntry:
            YYAutoreleasePoolPush();
            break;

        case kCFRunLoopBeforeWaiting:
            YYAutoreleasePoolPop();
            YYAutoreleasePoolPush();
            break;

        case kCFRunLoopExit:
            YYAutoreleasePoolPop();
            break;

        default:
            break;
    }
}

// MARK: - Setup 函数
static void YYRunloopAutoreleasePoolSetup(void) {
    CFRunLoopRef runloop = CFRunLoopGetCurrent();

    // Observer: 在 Runloop Entry 时 Push
    CFRunLoopObserverRef pushObserver = CFRunLoopObserverCreate(
        kCFAllocatorDefault,
        kCFRunLoopEntry,
        true,               // repeat
        -0x7FFFFFFF,        // 优先级最高（最早执行）
        YYRunLoopAutoreleasePoolObserverCallback,
        NULL
    );
    CFRunLoopAddObserver(runloop, pushObserver, kCFRunLoopCommonModes);
    CFRelease(pushObserver);

    // Observer: 在 BeforeWaiting 和 Exit 时 Pop
    CFRunLoopObserverRef popObserver = CFRunLoopObserverCreate(
        kCFAllocatorDefault,
        kCFRunLoopBeforeWaiting | kCFRunLoopExit,
        true,               // repeat
        0x7FFFFFFF,         // 优先级最低（最后执行）
        YYRunLoopAutoreleasePoolObserverCallback,
        NULL
    );
    CFRunLoopAddObserver(runloop, popObserver, kCFRunLoopCommonModes);
    CFRelease(popObserver);
}

// MARK: - 公共接口
@implementation NSThread (YYAdd)

+ (void)addAutoreleasePoolToCurrentRunloop {
    // 主线程已有 autorelease pool，无需添加
    if ([NSThread isMainThread]) return;

    NSThread *currentThread = [NSThread currentThread];
    if (!currentThread) return;

    // 防止重复添加
    if (currentThread.threadDictionary[YYNSThreadAutoreleasePoolKey]) return;

    // 设置 Runloop 的 autorelease pool 监听
    YYRunloopAutoreleasePoolSetup();

    // 标记已添加
    currentThread.threadDictionary[YYNSThreadAutoreleasePoolKey] = @YES;
}

@end
